#include "net/InetAddress.h"
#include "Base/Logger.h"
#include "Base/CurrectThread.h"
#include <cstring>
#include <sys/socket.h>
#include <stdlib.h>
#include <cstdio>

namespace toym
{
namespace net
{

InetAddress::InetAddress(short port)
    : m_pIpPortStr(nullptr)
{
    std::memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin_family = AF_INET;
    m_addr.sin_addr.s_addr = ::htons(INADDR_ANY);
    m_addr.sin_port = ::htons(port);
}

InetAddress::InetAddress(const char* ip, short port)
    : m_pIpPortStr(nullptr)
{
    if (ip == nullptr) {
        LOG_ERROR << "invalid ip: nullptr";
        ::abort();
    }
    std::memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin_family = AF_INET;
    m_addr.sin_port = ::htons(port);
    int ret = ::inet_pton(AF_INET, ip, &(m_addr.sin_addr));
    if (ret == 0) {
        LOG_ERROR << "invalid ip: " << ip;
        ::abort();
    }
    if (ret < 0) {
        CurrectThread::saveErrno(errno);
        LOG_ERROR << "InetAddress::InetAddress inet_pton fail";
        CurrectThread::saveErrno(0);
        ::abort();
    }
}

InetAddress::InetAddress(const std::string& ip, short port) 
    : InetAddress(ip.c_str(), port)
{}

short InetAddress::getPort() {
    return ::ntohs(m_addr.sin_port);
}

const char* InetAddress::toIpPort() const {
    char buf[20];
    if (m_pIpPortStr == nullptr) {
        const char* ret = ::inet_ntop(AF_INET, &(m_addr.sin_addr),buf, sizeof(buf));
        if (ret == 0) {
            CurrectThread::saveErrno(errno);
            LOG_ERROR << "InetAddress::toIpPort: inet_ntop fail";
            CurrectThread::saveErrno(0);
            ::abort();
        }
        std::snprintf(m_ipPortStr, sizeof(m_ipPortStr), "%s:%hu", buf, ::ntohs(m_addr.sin_port));
        m_pIpPortStr = m_ipPortStr;
    }
    return m_pIpPortStr;
}

std::string InetAddress::toString() const {
    return std::string(toIpPort());
}

void InetAddress::update(struct sockaddr_in* addr) {
    assert(addr != nullptr);
    std::memmove(&m_addr, addr, sizeof(m_addr));
    m_pIpPortStr = nullptr;
}

} // namespace net

} // namespace toym
